home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1995 March / macformat-022.iso / Shareware City / Developers / src / out-of-phase-102-c / OutOfPhase 1.02 Source / OutOfPhase Folder / Level 1 Extensions 29Sep94 / BufferedFileOutput.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-11-23  |  9.9 KB  |  317 lines  |  [TEXT/KAHL]

  1. /* BufferedFileOutput.c */
  2. /*****************************************************************************/
  3. /*                                                                           */
  4. /*    System Dependency Library for Building Portable Software               */
  5. /*    Macintosh Version                                                      */
  6. /*    Written by Thomas R. Lawrence, 1993 - 1994.                            */
  7. /*                                                                           */
  8. /*    This file is Public Domain; it may be used for any purpose whatsoever  */
  9. /*    without restriction.                                                   */
  10. /*                                                                           */
  11. /*    This package is distributed in the hope that it will be useful,        */
  12. /*    but WITHOUT ANY WARRANTY; without even the implied warranty of         */
  13. /*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.                   */
  14. /*                                                                           */
  15. /*    Thomas R. Lawrence can be reached at tomlaw@world.std.com.             */
  16. /*                                                                           */
  17. /*****************************************************************************/
  18.  
  19. #include "MiscInfo.h"
  20. #include "Audit.h"
  21. #include "Debug.h"
  22. #include "Definitions.h"
  23.  
  24. #include "BufferedFileOutput.h"
  25. #include "Files.h"
  26. #include "Memory.h"
  27.  
  28.  
  29. #define BUFFERSIZE (4096) /* must be a power of two! */
  30. #define BUFFERMASK (BUFFERSIZE - 1)
  31.  
  32.  
  33. struct BufferedOutputRec
  34.     {
  35.         FileType*                FileDescriptor;
  36.         long                        IndexIntoBuffer;
  37.         long                        IndexIntoFileOfStartOfBuffer;
  38.         MyBoolean                ErrorOcurredCantBeUsed;
  39.         char                        Buffer[BUFFERSIZE];
  40.     };
  41.  
  42.  
  43. /* create a new buffered output object around a file.  the file is not allowed */
  44. /* to be tampered with after it has been registered with this since I am too */
  45. /* lazy to implement proper buffering in the Level 0 library like I should. */
  46. BufferedOutputRec*    NewBufferedOutput(struct FileType* TheFileDescriptor)
  47.     {
  48.         long                                FileIndex;
  49.         BufferedOutputRec*    BufferedThang;
  50.  
  51.         CheckPtrExistence(TheFileDescriptor);
  52.  
  53.         BufferedThang = (BufferedOutputRec*)AllocPtrCanFail(sizeof(BufferedOutputRec),
  54.             "BufferedOutputRec");
  55.         if (BufferedThang == NIL)
  56.             {
  57.              FailurePoint1:
  58.                 return NIL;
  59.             }
  60.  
  61.         BufferedThang->FileDescriptor = TheFileDescriptor;
  62.  
  63.         FileIndex = GetFilePosition(TheFileDescriptor);
  64.         BufferedThang->IndexIntoBuffer = FileIndex & BUFFERMASK;
  65.         BufferedThang->IndexIntoFileOfStartOfBuffer = FileIndex & (~BUFFERMASK);
  66.  
  67.         ERROR(GetFileLength(TheFileDescriptor) > FileIndex,PRERR(ForceAbort,
  68.             "BufferedOutputRec:  can't be used for writing into the middle of a file"));
  69.  
  70.         BufferedThang->ErrorOcurredCantBeUsed = False;
  71.  
  72.         /* preload the buffer */
  73.         if (!SetFilePosition(TheFileDescriptor,BufferedThang->IndexIntoFileOfStartOfBuffer))
  74.             {
  75.              FailurePoint2:
  76.                 ReleasePtr((char*)BufferedThang);
  77.                 goto FailurePoint1;
  78.             }
  79.         if (0 != ReadFromFile(TheFileDescriptor,&(BufferedThang->Buffer[0]),
  80.             BufferedThang->IndexIntoBuffer))
  81.             {
  82.              FailurePoint3:
  83.                 goto FailurePoint2;
  84.             }
  85.         if (!SetFilePosition(TheFileDescriptor,BufferedThang->IndexIntoFileOfStartOfBuffer))
  86.             {
  87.              FailurePoint4:
  88.                 ReleasePtr((char*)BufferedThang);
  89.                 goto FailurePoint3;
  90.             }
  91.  
  92.         return BufferedThang;
  93.     }
  94.  
  95.  
  96. static MyBoolean        FlushBuffers(BufferedOutputRec* BufferedThang)
  97.     {
  98.         MyBoolean                    Successful;
  99.  
  100.         CheckPtrExistence(BufferedThang);
  101.         ERROR(BufferedThang->ErrorOcurredCantBeUsed,PRERR(ForceAbort,
  102.             "FlushBuffers:  error flag is set"));
  103.         ERROR(GetFilePosition(BufferedThang->FileDescriptor)
  104.             != BufferedThang->IndexIntoFileOfStartOfBuffer,PRERR(ForceAbort,
  105.             "FlushBuffers:  file and buffer pointers are out of sync"));
  106.         Successful = (0 == WriteToFile(BufferedThang->FileDescriptor,
  107.             &(BufferedThang->Buffer[0]),BufferedThang->IndexIntoBuffer));
  108.         if (!Successful)
  109.             {
  110.                 BufferedThang->ErrorOcurredCantBeUsed = True;
  111.             }
  112.         return Successful;
  113.     }
  114.  
  115.  
  116. /* clean up a buffered output object from around a file.  the file may be */
  117. /* used normally after this has been called.  if it failed to write the */
  118. /* data out to disk, then it returns False. */
  119. MyBoolean                        EndBufferedOutput(BufferedOutputRec* BufferedThang)
  120.     {
  121.         MyBoolean                    SuccessFlag;
  122.  
  123.         CheckPtrExistence(BufferedThang);
  124.  
  125.         if (!BufferedThang->ErrorOcurredCantBeUsed)
  126.             {
  127.                 SuccessFlag = FlushBuffers(BufferedThang);
  128.             }
  129.          else
  130.             {
  131.                 SuccessFlag = True;
  132.             }
  133.  
  134.         ReleasePtr((char*)BufferedThang);
  135.  
  136.         return SuccessFlag;
  137.     }
  138.  
  139.  
  140. /* write a raw block of data to the file.  it returns 0 if it wrote all of the */
  141. /* data in or however many bytes were not able to be written. */
  142. MyBoolean                        WriteBufferedOutput(BufferedOutputRec* BufferedThang,
  143.                                             long RequestedBytes, char* PlaceToGetFrom)
  144.     {
  145.         CheckPtrExistence(BufferedThang);
  146.         ERROR(RequestedBytes < 0,PRERR(ForceAbort,
  147.             "WriteBufferedOutput:  bad requested bytes"));
  148.         ERROR(BufferedThang->ErrorOcurredCantBeUsed,PRERR(ForceAbort,
  149.             "WriteBufferedOutput:  error flag is set"));
  150.  
  151.         /* output into the current buffer */
  152.         while ((RequestedBytes > 0) && (BufferedThang->IndexIntoBuffer < BUFFERSIZE))
  153.             {
  154.                 BufferedThang->Buffer[BufferedThang->IndexIntoBuffer] = *PlaceToGetFrom;
  155.                 PlaceToGetFrom += 1;
  156.                 BufferedThang->IndexIntoBuffer += 1;
  157.                 RequestedBytes -= 1;
  158.             }
  159.         /* flush the buffer */
  160.         if (BufferedThang->IndexIntoBuffer == BUFFERSIZE)
  161.             {
  162.                 if (!FlushBuffers(BufferedThang))
  163.                     {
  164.                         BufferedThang->ErrorOcurredCantBeUsed = True;
  165.                         return False;
  166.                     }
  167.                 BufferedThang->IndexIntoBuffer = 0;
  168.                 BufferedThang->IndexIntoFileOfStartOfBuffer += BUFFERSIZE;
  169.             }
  170.         if (RequestedBytes == 0)
  171.             {
  172.                 /* all done! */
  173.                 return True;
  174.             }
  175.  
  176.         /* write out whole blocks while there's enough to do */
  177.         while (RequestedBytes >= BUFFERSIZE)
  178.             {
  179.                 if (0 != WriteToFile(BufferedThang->FileDescriptor,PlaceToGetFrom,BUFFERSIZE))
  180.                     {
  181.                         BufferedThang->ErrorOcurredCantBeUsed = True;
  182.                         return False;
  183.                     }
  184.                 BufferedThang->IndexIntoFileOfStartOfBuffer += BUFFERSIZE;
  185.                 RequestedBytes -= BUFFERSIZE;
  186.                 PlaceToGetFrom += BUFFERSIZE;
  187.             }
  188.         if (RequestedBytes == 0)
  189.             {
  190.                 /* hmm done */
  191.                 return True;
  192.             }
  193.  
  194.         /* write out bytes into the final block */
  195.         while (RequestedBytes > 0)
  196.             {
  197.                 BufferedThang->Buffer[BufferedThang->IndexIntoBuffer] = *PlaceToGetFrom;
  198.                 PlaceToGetFrom += 1;
  199.                 BufferedThang->IndexIntoBuffer += 1;
  200.                 RequestedBytes -= 1;
  201.             }
  202.  
  203.         return True;
  204.     }
  205.  
  206.  
  207. /* write a signed character to the file.  returns True if successful. */
  208. MyBoolean                        WriteBufferedSignedChar(BufferedOutputRec* BufferedThang,
  209.                                             signed char SignedChar)
  210.     {
  211.         char                            Buff[1];
  212.  
  213.         CheckPtrExistence(BufferedThang);
  214.         Buff[0] = SignedChar;
  215.         return WriteBufferedOutput(BufferedThang,1,Buff);
  216.     }
  217.  
  218.  
  219. /* write an unsigned character to the file.  returns True if successful. */
  220. MyBoolean                        WriteBufferedUnsignedChar(BufferedOutputRec* BufferedThang,
  221.                                             unsigned char UnsignedChar)
  222.     {
  223.         char                            Buff[1];
  224.  
  225.         CheckPtrExistence(BufferedThang);
  226.         Buff[0] = UnsignedChar;
  227.         return WriteBufferedOutput(BufferedThang,1,Buff);
  228.     }
  229.  
  230.  
  231. /* write a signed 2's complement 16-bit short little endian.  returns True if successful */
  232. MyBoolean                        WriteBufferedSignedShortLittleEndian(BufferedOutputRec* BufferedThang,
  233.                                             signed short SignedShort)
  234.     {
  235.         char                            Buff[2];
  236.  
  237.         CheckPtrExistence(BufferedThang);
  238.         Buff[0] = SignedShort & 0xff;
  239.         Buff[1] = (SignedShort >> 8) & 0xff;
  240.         return WriteBufferedOutput(BufferedThang,2,Buff);
  241.     }
  242.  
  243.  
  244. /* write a signed 2's complement 16-bit short big endian.  returns True if successful */
  245. MyBoolean                        WriteBufferedSignedShortBigEndian(BufferedOutputRec* BufferedThang,
  246.                                             signed short SignedShort)
  247.     {
  248.         char                            Buff[2];
  249.  
  250.         CheckPtrExistence(BufferedThang);
  251.         Buff[1] = SignedShort & 0xff;
  252.         Buff[0] = (SignedShort >> 8) & 0xff;
  253.         return WriteBufferedOutput(BufferedThang,2,Buff);
  254.     }
  255.  
  256.  
  257. /* write an unsigned 16-bit short little endian.  returns True if successful. */
  258. MyBoolean                        WriteBufferedUnsignedShortLittleEndian(BufferedOutputRec* BufferedThang,
  259.                                             unsigned short UnsignedShort)
  260.     {
  261.         return WriteBufferedSignedShortLittleEndian(BufferedThang,UnsignedShort);
  262.     }
  263.  
  264.  
  265. /* write an unsigned 16-bit short big endian.  returns True if successful. */
  266. MyBoolean                        WriteBufferedUnsignedShortBigEndian(BufferedOutputRec* BufferedThang,
  267.                                             unsigned short UnsignedShort)
  268.     {
  269.         return WriteBufferedSignedShortBigEndian(BufferedThang,UnsignedShort);
  270.     }
  271.  
  272.  
  273. /* write a signed 2's complement 32-bit long little endian.  returns True if successful */
  274. MyBoolean                        WriteBufferedSignedLongLittleEndian(BufferedOutputRec* BufferedThang,
  275.                                             signed long SignedLong)
  276.     {
  277.         char                            Buff[4];
  278.  
  279.         CheckPtrExistence(BufferedThang);
  280.         Buff[0] = SignedLong & 0xff;
  281.         Buff[1] = (SignedLong >> 8) & 0xff;
  282.         Buff[2] = (SignedLong >> 16) & 0xff;
  283.         Buff[3] = (SignedLong >> 24) & 0xff;
  284.         return WriteBufferedOutput(BufferedThang,4,Buff);
  285.     }
  286.  
  287.  
  288. /* write a signed 2's complement 32-bit long big endian.  returns True if successful */
  289. MyBoolean                        WriteBufferedSignedLongBigEndian(BufferedOutputRec* BufferedThang,
  290.                                             signed long SignedLong)
  291.     {
  292.         char                            Buff[4];
  293.  
  294.         CheckPtrExistence(BufferedThang);
  295.         Buff[3] = SignedLong & 0xff;
  296.         Buff[2] = (SignedLong >> 8) & 0xff;
  297.         Buff[1] = (SignedLong >> 16) & 0xff;
  298.         Buff[0] = (SignedLong >> 24) & 0xff;
  299.         return WriteBufferedOutput(BufferedThang,4,Buff);
  300.     }
  301.  
  302.  
  303. /* write an unsigned 32-bit long little endian.  returns True if successful */
  304. MyBoolean                        WriteBufferedUnsignedLongLittleEndian(BufferedOutputRec* BufferedThang,
  305.                                             unsigned long UnsignedLong)
  306.     {
  307.         return WriteBufferedSignedLongLittleEndian(BufferedThang,UnsignedLong);
  308.     }
  309.  
  310.  
  311. /* write an unsigned 32-bit long big endian.  returns True if successful */
  312. MyBoolean                        WriteBufferedUnsignedLongBigEndian(BufferedOutputRec* BufferedThang,
  313.                                             unsigned long UnsignedLong)
  314.     {
  315.         return WriteBufferedSignedLongBigEndian(BufferedThang,UnsignedLong);
  316.     }
  317.